#include "comm/znx_slru.h"

typedef struct {
    int    key;
    size_t size;
} znx_test_node_t;

static inline size_t
test_node_size_get(void *data) {
    znx_test_node_t *node = data;
    return node->size;
}

static inline int
test_node_cmp(void *data_a, void *data_b)
{
    znx_test_node_t *node_a = (znx_test_node_t *)data_a;
    znx_test_node_t *node_b = (znx_test_node_t *)data_b;

    if (node_a->key == node_b->key) {
        return 0;
    }

    return node_a->key > node_b->key ? 1 : -1;
}

static inline void
test_node_free(void *data)
{
    znx_test_node_t *node = data;
    znx_thread_free(node);
}

void test_s1lru()
{
    znx_slru_t *slru = znx_slru_create(
        1, 3, 5,
        test_node_size_get,
        test_node_free,
        test_node_cmp);

    znx_test_node_t *node1 = znx_thread_calloc(sizeof(znx_test_node_t));
    node1->key = 1;
    node1->size = 1;

    znx_test_node_t *node2 = znx_thread_calloc(sizeof(znx_test_node_t));
    node2->key = 2;
    node2->size = 1;

    znx_test_node_t *node3 = znx_thread_calloc(sizeof(znx_test_node_t));
    node3->key = 3;
    node3->size = 1;

    znx_test_node_t *node4 = znx_thread_calloc(sizeof(znx_test_node_t));
    node4->key = 4;
    node4->size = 1;

    znx_slru_put(slru, node1);
    znx_slru_put(slru, node2);
    znx_slru_put(slru, node3);
    znx_slru_put(slru, node4);


    void *data = NULL;
    znx_test_node_t target;

    target.key = 1;
    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except not found");
    }

    target.key = 2;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 2) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 2, but got %d", ((znx_test_node_t *)data)->key);
    }

    target.key = 3;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 3) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 3, but got %d", ((znx_test_node_t *)data)->key);
    }

    target.key = 4;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 4) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 4, but got %d", ((znx_test_node_t *)data)->key);
    }

    znx_slru_destroy(slru);

    slru = znx_slru_create(
        1, 3, 5,
        test_node_size_get,
        test_node_free,
        test_node_cmp);

    node1 = znx_thread_calloc(sizeof(znx_test_node_t));
    node1->key = 1;
    node1->size = 3;

    node2 = znx_thread_calloc(sizeof(znx_test_node_t));
    node2->key = 2;
    node2->size = 3;

    node3 = znx_thread_calloc(sizeof(znx_test_node_t));
    node3->key = 3;
    node3->size = 3;

    node4 = znx_thread_calloc(sizeof(znx_test_node_t));
    node4->key = 4;
    node4->size = 3;

    znx_slru_put(slru, node1);
    znx_slru_put(slru, node2);
    znx_slru_put(slru, node3);
    znx_slru_put(slru, node4);

    target.key = 1;
    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except not found");
    }

    target.key = 2;
    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except not found");
    }

    target.key = 3;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 3) {
        ZNX_DEF_LOG_FATAL(NULL, "except 3, but got %d", ((znx_test_node_t *)data)->key);
    }

    target.key = 4;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 4) {
        ZNX_DEF_LOG_FATAL(NULL, "except 4, but got %d", ((znx_test_node_t *)data)->key);
    }

    target.key = 4;
    if (!znx_slru_remove(slru, &target)) {
        ZNX_DEF_LOG_FATAL(NULL, "expect true, but got false");
    }

    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except not found");
    }

    znx_test_node_t *node5 = znx_thread_calloc(sizeof(znx_test_node_t));
    node5->key = 5;
    node5->size = 3;

    znx_slru_put(slru, node5);

    target.key = 3;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "expect found");
    }

    znx_test_node_t *node6 = znx_thread_calloc(sizeof(znx_test_node_t));
    node6->key = 6;
    node6->size = 3;
    znx_slru_put(slru, node6);

    target.key = 5;
    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "expect not found");
    }

    target.key = 6;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "expect found");
    }

    target.key = 3;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "expect found");
    }

    znx_slru_destroy(slru);
}

void test_s3lru()
{
    znx_slru_t *slru = znx_slru_create(
        3, 9, 0,
        test_node_size_get,
        test_node_free,
        test_node_cmp);

    znx_test_node_t *node1 = znx_thread_calloc(sizeof(znx_test_node_t));
    node1->key = 1;
    node1->size = 1;

    znx_test_node_t *node2 = znx_thread_calloc(sizeof(znx_test_node_t));
    node2->key = 2;
    node2->size = 1;

    znx_test_node_t *node3 = znx_thread_calloc(sizeof(znx_test_node_t));
    node3->key = 3;
    node3->size = 1;

    znx_test_node_t *node4 = znx_thread_calloc(sizeof(znx_test_node_t));
    node4->key = 4;
    node4->size = 1;

    znx_slru_put(slru, node1);
    znx_slru_put(slru, node2);
    znx_slru_put(slru, node3);
    znx_slru_put(slru, node4);

    void *data = NULL;
    znx_test_node_t target;

    target.key = 1;
    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except not found");
    }

    target.key = 2;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 2) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 2, but got %d", ((znx_test_node_t *)data)->key);
    }

    target.key = 3;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 3) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 3, but got %d", ((znx_test_node_t *)data)->key);
    }

    target.key = 4;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 4) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 4, but got %d", ((znx_test_node_t *)data)->key);
    }


    // move to list-3
    target.key = 4;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 4) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 4, but got %d", ((znx_test_node_t *)data)->key);
    }

    // move to list-3 head.
    target.key = 4;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    if (((znx_test_node_t *)data)->key != 4) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 4, but got %d", ((znx_test_node_t *)data)->key);
    }

    znx_test_node_t *node5 = znx_thread_calloc(sizeof(znx_test_node_t));
    node5->key = 5;
    node5->size = 1;

    znx_test_node_t *node6 = znx_thread_calloc(sizeof(znx_test_node_t));
    node6->key = 6;
    node6->size = 1;

    znx_test_node_t *node7 = znx_thread_calloc(sizeof(znx_test_node_t));
    node7->key = 7;
    node7->size = 1;

    znx_test_node_t *node8 = znx_thread_calloc(sizeof(znx_test_node_t));
    node8->key = 8;
    node8->size = 1;

    znx_slru_put(slru, node5);
    znx_slru_put(slru, node6);
    znx_slru_put(slru, node7);
    znx_slru_put(slru, node8);

    target.key = 2;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    target.key = 3;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    target.key = 4;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    target.key = 6;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    target.key = 7;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    target.key = 8;
    if (!znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except found");
    }

    target.key = 5;
    if (znx_slru_get(slru, &target, &data)) {
        ZNX_DEF_LOG_FATAL(NULL, "except not found");
    }

    znx_slru_destroy(slru);
}


int main()
{
    test_s1lru();
    test_s3lru();

    return 0;
}
